﻿using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Security.Cryptography;

namespace qip_history_synchronizer.Pop3
{
    /// <summary>
    /// POP3 Client.
    /// </summary>
    /// <example>
    /// <code>
    ///
    /// /*
    ///  To make this code to work, you need to import following namespaces:
    ///  using LumiSoft.Net.Mime;
    ///  using LumiSoft.Net.POP3.Client;
    ///  */
    ///
    /// using(POP3_Client c = new POP3_Client()){
    ///		c.Connect("ivx",110);
    ///		c.Authenticate("test","test",true);
    ///
    ///		POP3_MessagesInfo mInf = c.GetMessagesInfo();
    ///
    ///		// Get first message if there is any
    ///		if(mInf.Count > 0){
    ///			byte[] messageData = c.GetMessage(mInf[0]);
    ///
    ///			// Do your suff
    ///
    ///			// Parse message
    ///			Mime m = Mime.Parse(messageData);
    ///			string from = m.MainEntity.From;
    ///			string subject = m.MainEntity.Subject;
    ///			// ...
    ///		}
    ///	}
    /// </code>
    /// </example>
    /// 
    class Pop3Client : IDisposable
    {
        //private SocketEx     m_pSocket       = null;
        //private SocketLogger m_pLogger       = null;
        //private bool         m_Connected     = false;
        //private bool         m_Authenticated = false;
        //private string       m_ApopHashKey   = "";
        //private bool         m_LogCmds       = false;

        ///// <summary>
        ///// Occurs when POP3 session has finished and session log is available.
        ///// </summary>
        //public event LogEventHandler SessionLog = null;

        ///// <summary>
        ///// Default constructor.
        ///// </summary>
        //public POP3_Client()
        //{
        //}

        //#region method Dispose

        ///// <summary>
        ///// Clean up any resources being used.
        ///// </summary>
        //public void Dispose()
        //{
        //    try{
        //        Disconnect();
        //    }
        //    catch{
        //    }
        //}

        //#endregion


        //#region method Connect

        ///// <summary>
        ///// Connects to specified host.
        ///// </summary>
        ///// <param name="host">Host name.</param>
        ///// <param name="port">Port number. Default POP3 port is 110.</param>
        //public void Connect(string host,int port)
        //{
        //    Connect(host,port,false);
        //}

        ///// <summary>
        ///// Connects to specified host.
        ///// </summary>
        ///// <param name="host">Host name.</param>
        ///// <param name="port">Port number. Default POP3 port is 110 and SSL port is 995.</param>
        ///// <param name="ssl">Specifies if to connected via SSL.</param>
        //public void Connect(string host,int port,bool ssl)
        //{
        //    if(!m_Connected){
        //        SocketEx s = new SocketEx();
        //        s.Connect(host,port,ssl);
        //        m_pSocket = s;

        //        if(m_LogCmds && SessionLog != null){
        //            m_pLogger = new SocketLogger(s.RawSocket,SessionLog);
        //            m_pLogger.SessionID = Guid.NewGuid().ToString();
        //            m_pSocket.Logger = m_pLogger;
        //        }

        //        // Set connected flag
        //        m_Connected = true;

        //        string reply = m_pSocket.ReadLine();
        //        if(reply.StartsWith("+OK")){
        //            // Try to read APOP hash key, if supports APOP
        //            if(reply.IndexOf("<") > -1 && reply.IndexOf(">") > -1){
        //                m_ApopHashKey = reply.Substring(reply.LastIndexOf("<"),reply.LastIndexOf(">") - reply.LastIndexOf("<") + 1);
        //            }
        //        }
        //    }
        //}

        //#endregion

        //#region method Disconnect

        ///// <summary>
        ///// Closes connection to POP3 server.
        ///// </summary>
        //public void Disconnect()
        //{
        //    try{
        //        if(m_pSocket != null){
        //            // Send QUIT
        //            m_pSocket.WriteLine("QUIT");

        //            m_pSocket.Shutdown(SocketShutdown.Both);
        //        }
        //    }
        //    catch{
        //    }

        //    if(m_pLogger != null){
        //        m_pLogger.Flush();
        //    }
        //    m_pLogger = null;

        //    m_pSocket       = null;
        //    m_Connected     = false;
        //    m_Authenticated = false;
        //}

        //#endregion

        //#region method StartTLS

        ///// <summary>
        ///// Switches POP3 connection to SSL.
        ///// </summary>
        //public void StartTLS()
        //{
        //    /* RFC 2595 4. POP3 STARTTLS extension.
        //        Arguments: none

        //        Restrictions:
        //            Only permitted in AUTHORIZATION state.

        //        Possible Responses:
        //             +OK -ERR

        //         Examples:
        //             C: STLS
        //             S: +OK Begin TLS negotiation
        //             <TLS negotiation, further commands are under TLS layer>
        //               ...
        //             C: STLS
        //             S: -ERR Command not permitted when TLS active
        //    */

        //    if(!m_Connected){
        //        throw new Exception("You must connect first !");
        //    }
        //    if(m_Authenticated){
        //        throw new Exception("The STLS command is only valid in non-authenticated state !");
        //    }
        //    if(m_pSocket.SSL){
        //        throw new Exception("Connection is already secure !");
        //    }

        //    m_pSocket.WriteLine("STLS");

        //    string reply = m_pSocket.ReadLine();
        //    if(!reply.ToUpper().StartsWith("+OK")){
        //        throw new Exception("Server returned:" + reply);
        //    }

        //    m_pSocket.SwitchToSSL_AsClient();
        //}

        //#endregion

        //#region method Authenticate

        ///// <summary>
        ///// Authenticates user.
        ///// </summary>
        ///// <param name="userName">User login name.</param>
        ///// <param name="password">Password.</param>
        ///// <param name="tryApop"> If true and POP3 server supports APOP, then APOP is used, otherwise normal login used.</param>
        //public void Authenticate(string userName,string password,bool tryApop)
        //{
        //    if(!m_Connected){
        //        throw new Exception("You must connect first !");
        //    }

        //    if(m_Authenticated){
        //        throw new Exception("You are already authenticated !");
        //    }

        //    // Supports APOP, use it
        //    if(tryApop && m_ApopHashKey.Length > 0){
        //        //--- Compute md5 hash -----------------------------------------------//
        //        byte[] data = System.Text.Encoding.ASCII.GetBytes(m_ApopHashKey + password);

        //        MD5 md5 = new MD5CryptoServiceProvider();
        //        byte[] hash = md5.ComputeHash(data);

        //        string hexHash = BitConverter.ToString(hash).ToLower().Replace("-","");
        //        //---------------------------------------------------------------------//

        //        m_pSocket.WriteLine("APOP " + userName + " " + hexHash);

        //        string reply = m_pSocket.ReadLine();
        //        if(reply.StartsWith("+OK")){
        //            m_Authenticated = true;
        //        }
        //        else{
        //            throw new Exception("Server returned:" + reply);
        //        }
        //    }
        //    else{ // Use normal LOGIN, don't support APOP
        //        m_pSocket.WriteLine("USER " + userName);

        //        string reply = m_pSocket.ReadLine();
        //        if(reply.StartsWith("+OK")){
        //            m_pSocket.WriteLine("PASS " + password);

        //            reply = m_pSocket.ReadLine();
        //            if(reply.StartsWith("+OK")){
        //                m_Authenticated = true;
        //            }
        //            else{
        //                throw new Exception("Server returned:" + reply);
        //            }
        //        }
        //        else{
        //            throw new Exception("Server returned:" + reply);
        //        }
        //    }

        //    if(m_Authenticated && m_pSocket.Logger != null){
        //        m_pSocket.Logger.UserName = userName;
        //    }
        //}

        //#endregion


        //#region function GetMessagesInfo

        ///// <summary>
        ///// Gets messages info.
        ///// </summary>
        //public POP3_MessagesInfo GetMessagesInfo()
        //{
        //    if(!m_Connected){
        //        throw new Exception("You must connect first !");
        //    }

        //    if(!m_Authenticated){
        //        throw new Exception("You must authenticate first !");
        //    }

        //    POP3_MessagesInfo messagesInfo = new POP3_MessagesInfo();

        //    // Before getting list get UIDL list, then we can make full message info (UID,No,Size).
        //    Hashtable uidlList = GetUidlList();

        //    m_pSocket.WriteLine("LIST");

        //    /* NOTE: If reply is +OK, this is multiline respone and is terminated with '.'.
        //    Examples:
        //        C: LIST
        //        S: +OK 2 messages (320 octets)
        //        S: 1 120
        //        S: 2 200
        //        S: .
        //        ...
        //        C: LIST 3
        //        S: -ERR no such message, only 2 messages in maildrop
        //    */

        //    // Read first line of reply, check if it's ok
        //    string line = m_pSocket.ReadLine();
        //    if(line.StartsWith("+OK")){
        //        // Read lines while get only '.' on line itshelf.
        //        while(true){
        //            line = m_pSocket.ReadLine();

        //            // End of data
        //            if(line.Trim() == "."){
        //                break;
        //            }
        //            else{
        //                string[] param = line.Trim().Split(new char[]{' '});
        //                int  no   = Convert.ToInt32(param[0]);
        //                long size = Convert.ToInt64(param[1]);

        //                messagesInfo.Add(uidlList[no].ToString(),no,size);
        //            }
        //        }
        //    }
        //    else{
        //        throw new Exception("Server returned:" + line);
        //    }

        //    return messagesInfo;
        //}

        //#endregion

        //#region function GetUidlList

        ///// <summary>
        ///// Gets uid listing.
        ///// </summary>
        ///// <returns>Returns Hashtable containing uidl listing. Key column contains message NR and value contains message UID.</returns>
        //public Hashtable GetUidlList()
        //{
        //    if(!m_Connected){
        //        throw new Exception("You must connect first !");
        //    }

        //    if(!m_Authenticated){
        //        throw new Exception("You must authenticate first !");
        //    }

        //    Hashtable retVal = new Hashtable();

        //    m_pSocket.WriteLine("UIDL");

        //    /* NOTE: If reply is +OK, this is multiline respone and is terminated with '.'.
        //    Examples:
        //        C: UIDL
        //        S: +OK
        //        S: 1 whqtswO00WBw418f9t5JxYwZ
        //        S: 2 QhdPYR:00WBw1Ph7x7
        //        S: .
        //        ...
        //        C: UIDL 3
        //        S: -ERR no such message
        //    */

        //    // Read first line of reply, check if it's ok
        //    string line = m_pSocket.ReadLine();
        //    if(line.StartsWith("+OK")){
        //        // Read lines while get only '.' on line itshelf.
        //        while(true){
        //            line = m_pSocket.ReadLine();

        //            // End of data
        //            if(line.Trim() == "."){
        //                break;
        //            }
        //            else{
        //                string[] param = line.Trim().Split(new char[]{' '});
        //                int    nr  = Convert.ToInt32(param[0]);
        //                string uid = param[1];

        //                retVal.Add(nr,uid);
        //            }
        //        }
        //    }
        //    else{
        //        throw new Exception("Server returned:" + line);
        //    }

        //    return retVal;
        //}

        //#endregion

        //#region method GetMessage

        ///// <summary>
        ///// Gets specified message.
        ///// </summary>
        ///// <param name="msgInfo">Pop3 message info of message what to get.</param>
        ///// <returns></returns>
        //public byte[] GetMessage(POP3_MessageInfo msgInfo)
        //{
        //    return GetMessage(msgInfo.MessageNumber);
        //}

        ///// <summary>
        ///// Gets specified message.
        ///// </summary>
        ///// <param name="messageNo">Message number.</param>
        //public byte[] GetMessage(int messageNo)
        //{
        //    MemoryStream stream = new MemoryStream();
        //    GetMessage(messageNo,stream);
        //    return stream.ToArray();
        //}

        ///// <summary>
        ///// Gets specified message and stores it to specified stream.
        ///// </summary>
        ///// <param name="messageNo">Message number.</param>
        ///// <param name="stream">Stream where to store message.</param>
        //public void GetMessage(int messageNo,Stream stream)
        //{
        //    if(!m_Connected){
        //        throw new Exception("You must connect first !");
        //    }

        //    if(!m_Authenticated){
        //        throw new Exception("You must authenticate first !");
        //    }

        //    m_pSocket.WriteLine("RETR " + messageNo.ToString());

        //    // Read first line of reply, check if it's ok
        //    string line = m_pSocket.ReadLine();
        //    if(line.StartsWith("+OK")){
        //        m_pSocket.ReadPeriodTerminated(stream,100000000);
        //    }
        //    else{
        //        throw new Exception("Server returned:" + line);
        //    }
        //}

        //#endregion

        //#region method DeleteMessage

        ///// <summary>
        ///// Deletes specified message
        ///// </summary>
        ///// <param name="messageNr">Message number.</param>
        //public void DeleteMessage(int messageNr)
        //{
        //    if(!m_Connected){
        //        throw new Exception("You must connect first !");
        //    }

        //    if(!m_Authenticated){
        //        throw new Exception("You must authenticate first !");
        //    }

        //    m_pSocket.WriteLine("DELE " + messageNr.ToString());

        //    // Read first line of reply, check if it's ok
        //    string line = m_pSocket.ReadLine();
        //    if(!line.StartsWith("+OK")){
        //        throw new Exception("Server returned:" + line);
        //    }
        //}

        //#endregion

        //#region method GetTopOfMessage

        ///// <summary>
        ///// Gets top lines of message.
        ///// </summary>
        ///// <param name="nr">Message number which top lines to get.</param>
        ///// <param name="nLines">Number of lines to get.</param>
        //public byte[] GetTopOfMessage(int nr,int nLines)
        //{
        //    if(!m_Connected){
        //        throw new Exception("You must connect first !");
        //    }

        //    if(!m_Authenticated){
        //        throw new Exception("You must authenticate first !");
        //    }


        //    m_pSocket.WriteLine("TOP " + nr.ToString() + " " + nLines.ToString());

        //    // Read first line of reply, check if it's ok
        //    string line = m_pSocket.ReadLine();
        //    if(line.StartsWith("+OK")){
        //        MemoryStream strm = new MemoryStream();
        //        m_pSocket.ReadPeriodTerminated(strm,100000000);

        //        return strm.ToArray();
        //    }
        //    else{
        //        throw new Exception("Server returned:" + line);
        //    }
        //}

        //#endregion

        //#region method Reset

        ///// <summary>
        ///// Resets session.
        ///// </summary>
        //public void Reset()
        //{
        //    if(!m_Connected){
        //        throw new Exception("You must connect first !");
        //    }

        //    if(!m_Authenticated){
        //        throw new Exception("You must authenticate first !");
        //    }

        //    m_pSocket.WriteLine("RSET");

        //    // Read first line of reply, check if it's ok
        //    string line = m_pSocket.ReadLine();
        //    if(!line.StartsWith("+OK")){
        //        throw new Exception("Server returned:" + line);
        //    }
        //}

        //#endregion


        //#region Properties Implementation

        ///// <summary>
        ///// Gets if pop3 client is connected.
        ///// </summary>
        //public bool Connected
        //{
        //    get{ return m_Connected; }
        //}

        ///// <summary>
        ///// Gets if pop3 client is authenticated.
        ///// </summary>
        //public bool Authenticated
        //{
        //    get{ return m_Authenticated; }
        //}

        ///// <summary>
        ///// Gets or sets if to log commands.
        ///// </summary>
        //public bool LogCommands
        //{
        //    get{ return m_LogCmds;	}

        //    set{ m_LogCmds = value; }
        //}

        ///// <summary>
        ///// Gets if the connection is an SSL connection.
        ///// </summary>
        //public bool IsSecureConnection
        //{
        //    get{
        //        if(!m_Connected){
        //            throw new Exception("You must connect first");
        //        }

        //        return m_pSocket.SSL;
        //    }
        //}

        //#endregion

        public void Dispose( )
        {
            throw new System.NotImplementedException( );
        }
    }
}